package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.article.dtos.ApArticleDto;
import com.heima.common.constants.WemediaConstants;
import com.heima.common.exception.CustomException;
import com.heima.feign.article.ArticleFeignClient;
import com.heima.model.common.dtos.PageRequestDto;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.wemedia.context.BaseContext;
import com.heima.wemedia.dtos.WmAuthDto;
import com.heima.wemedia.dtos.WmNewsDto;
import com.heima.wemedia.dtos.WmNewsPageReqDto;
import com.heima.wemedia.mapper.WmMaterialMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmNewsMaterialMapper;
import com.heima.wemedia.pojos.WmChannel;
import com.heima.wemedia.pojos.WmMaterial;
import com.heima.wemedia.pojos.WmNews;
import com.heima.wemedia.pojos.WmNewsMaterial;
import com.heima.wemedia.service.WmChannelService;
import com.heima.wemedia.service.WmNewsAutoScanService;
import com.heima.wemedia.service.WmNewsService;
import com.heima.wemedia.service.WmNewsTaskService;
import com.heima.wemedia.vos.WmNewsVo;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author 郭文杰
 * @description 针对表【wm_news(自媒体图文内容信息表)】的数据库操作Service实现
 * @createDate 2023-12-04 10:08:42
 */
@Service
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews>
        implements WmNewsService {

    @Autowired
    private WmNewsMapper wmNewsMapper;

    @Autowired
    private WmNewsMaterialMapper wmNewsMaterialMapper;

    @Autowired
    private WmMaterialMapper wmMaterialMapper;

    @Autowired
    private WmNewsAutoScanService wmNewsAutoScanService;

    @Autowired
    private WmChannelService wmChannelService;

    @Autowired
    private ArticleFeignClient articleFeignClient;

    @Autowired
    private WmNewsTaskService WmNewsTaskService;

    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;

    private WmNewsDto wmNewsDto;
    private PageRequestDto pageRequestDto;

    /**
     * 自媒体分页查询
     *
     * @param wmNewsPageReqDto 分页参数
     * @return 当前页
     */
    @Override
    public Page<WmNews> listPage(WmNewsPageReqDto wmNewsPageReqDto) {
        //获取当前登录人的信息
        Long userID = BaseContext.getCurrentId();
        if (userID == null) {
            throw new CustomException(AppHttpCodeEnum.NEED_LOGIN);
        }

        //非空校验
        if (wmNewsPageReqDto == null) {
            wmNewsPageReqDto = new WmNewsPageReqDto();
        }

        //检查分页参数
        wmNewsPageReqDto.checkParam();

        //分页查询
        Page<WmNews> page = new Page<>(wmNewsPageReqDto.getPage(), wmNewsPageReqDto.getSize());
        //查询条件
        LambdaQueryWrapper<WmNews> queryWrapper = new LambdaQueryWrapper<>();

        //状态判断
        queryWrapper.eq(
                wmNewsPageReqDto.getStatus() != null
                , WmNews::getStatus
                , wmNewsPageReqDto.getStatus());

        //开始时间判断
        queryWrapper.gt(
                wmNewsPageReqDto.getBeginPubDate() != null
                , WmNews::getPublishTime
                , wmNewsPageReqDto.getBeginPubDate());

        //结束时间判断
        queryWrapper.lt(
                wmNewsPageReqDto.getEndPubDate() != null
                , WmNews::getPublishTime
                , wmNewsPageReqDto.getEndPubDate());

        //频道判断
        queryWrapper.eq(
                wmNewsPageReqDto.getChannelId() != null
                , WmNews::getChannelId
                , wmNewsPageReqDto.getChannelId());

        //关键字判断
        queryWrapper.like(
                StringUtils.isNotEmpty(wmNewsPageReqDto.getKeyword())
                , WmNews::getTitle
                , wmNewsPageReqDto.getKeyword());

        //查询当前用户文章
        queryWrapper.eq(WmNews::getUserId, BaseContext.getCurrentId());

        queryWrapper.orderByDesc(WmNews::getCreatedTime);

        this.page(page, queryWrapper);

        return page;
    }

    /**
     * 文章发布
     *
     * @param wmNewsDto
     * @return
     */
    @Override
    public void submit(WmNewsDto wmNewsDto) {
        //校验是否登录
        Long userId = BaseContext.getCurrentId();
        if (userId == null) {
            throw new CustomException(AppHttpCodeEnum.NEED_LOGIN);
        }

        //校验参数是否合法
        if (wmNewsDto == null ||
                StringUtils.isEmpty(wmNewsDto.getContent()) ||
                StringUtils.isEmpty(wmNewsDto.getTitle())) {
            throw new CustomException(AppHttpCodeEnum.PARAM_REQUIRE);
        }

        //获取新增或修改的 自媒体图文内容
        WmNews wmNews = getWmNews(wmNewsDto);


        //1 判断图文是否存在
        Integer newsId = wmNewsDto.getId();
        if (newsId == null) {
            wmNews.setCreatedTime(new Date());//创建时间
            //1.1 不存在则新增文章
            this.save(wmNews);
        } else {
            //1.2 存在则 修改文章
            //删除关联素材关系
            LambdaQueryWrapper<WmNewsMaterial> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(WmNewsMaterial::getNewsId, newsId);
            wmNewsMaterialMapper.delete(queryWrapper);
            //修改文章
            this.updateById(wmNews);
        }

        //如果文章是草稿 直接结束
        if (wmNewsDto.getStatus() == 0) {
            return;
        }

        //2 保存自媒体内容图片与素材关系
        saveContentImageWmNewMaterial(wmNews);

        //3 保存自媒体封面图片与素材关系
        saveCoverImageWmNewMaterial(wmNewsDto, wmNews);

        //4 文章发布后 调用自动审核接口
        WmNewsTaskService.addNewsToTask(wmNews.getId(), wmNews.getPublishTime());
//        wmNewsAutoScanService.autoScanWmNews(wmNews.getId());

    }

    /**
     * 保存自媒体内容图片与素材关系
     *
     * @param wmNews 自媒体内容
     */
    private void saveContentImageWmNewMaterial(WmNews wmNews) {
        //2.1 解析json获取自媒体图文内容 图片
        List<String> newsContentImages = getContentImageList(wmNews);
        //设置图片
        wmNews.setImages(
                //判断原来是否有图片
                wmNews.getImages() == null ?
                        //如果没有,直接用上封面图片
                        StringUtils.join(newsContentImages, ",") :
                        //如果有图片片直接在后面拼接上封面图片
                        wmNews.getImages() + "," + StringUtils.join(newsContentImages, ",")
        );
        this.updateById(wmNews);
        //2.2 添加自媒体图片与素材关系
        addWmNewsMaterial(wmNews, newsContentImages, 0, WemediaConstants.WM_CONTENT_REFERENCE.intValue());
    }

    /**
     * 保存自媒体封面图片与素材关系
     *
     * @param wmNewsDto 前端的封面图片
     * @param wmNews    自媒体图文内容(设置了封面图片后,需要修改自媒体图文内容)
     */
    private void saveCoverImageWmNewMaterial(WmNewsDto wmNewsDto, WmNews wmNews) {
        //图片类型
        int type = WemediaConstants.WM_COVER_REFERENCE.intValue();

        //自动封面类型
        if (wmNewsDto.getType() == -1) {
            // 内容中的图片
            List<String> contentImageList = getContentImageList(wmNews);
            // 判断内容中图片个数
            int contentImagesSize = (contentImageList == null ? 0 : contentImageList.size());
            // 3.2 判断内容图片个数 决定是封面是单图、多图、无图
            //无图
            if (contentImagesSize == 0) {
                wmNews.setType(0);
            }
            //单图
            if (contentImagesSize >= 1 && contentImagesSize < 3) {
                //3.2.1 设置封面类型
                wmNews.setType(1);
                //获取第一张图片为封面
                List<String> coverImage = contentImageList.stream().limit(1).collect(Collectors.toList());
                //设置图片
                wmNews.setImages(
                        //判断原来是否有图片
                        wmNews.getImages() == null ?
                                //如果没有,直接用上封面图片
                                StringUtils.join(coverImage, ",") :
                                //如果有图片片直接在后面拼接上封面图片
                                wmNews.getImages() + "," + StringUtils.join(coverImage, ",")
                );
                //3.2.2 添加封面图片与素材关系
                addWmNewsMaterial(wmNews, coverImage, type, 1);
            }
            //多图
            if (contentImagesSize >= 3) {
                //设置封面类型
                wmNews.setType(3);
                //获取前三张图片为封面
                List<String> coverImage = contentImageList.stream().limit(3).collect(Collectors.toList());
                //设置图片
                wmNews.setImages(
                        //判断原来是否有图片
                        wmNews.getImages() == null ?
                                //如果没有,直接用上封面图片
                                StringUtils.join(coverImage, ",") :
                                //如果有图片片直接在后面拼接上封面图片
                                wmNews.getImages() + "," + StringUtils.join(coverImage, ",")
                );//设置封面图片
                addWmNewsMaterial(wmNews, coverImage, type, 2);
            }
            //修改自媒体图文状态为 提交(待审核)
            wmNews.setStatus(1);
            //修改自媒体文图文内容
            this.updateById(wmNews);
        }
        // 固定封面类型
        addWmNewsMaterial(wmNews, wmNewsDto.getImages(), type, 3);
    }

    /**
     * 获取新增或修改的 自媒体图文内容
     *
     * @param wmNewsDto 接收的前端参数
     * @return 自媒体图文内容
     */
    private WmNews getWmNews(WmNewsDto wmNewsDto) {
        WmNews wmNews = new WmNews();
        BeanUtils.copyProperties(wmNewsDto, wmNews);
        wmNews.setUserId(Integer.valueOf(BaseContext.getCurrentId() + ""));
        wmNews.setSubmitedTime(new Date());//提交时间
        wmNews.setStatus(wmNewsDto.getStatus().intValue());//待审核
        //设置封面类型
        if (wmNewsDto.getType() == -1) { //自动
            wmNews.setType(null);
            // wmNews.setType(Integer.valueOf(wmNewsDto.getType() + ""));
        } else { //固定
            wmNews.setType(wmNewsDto.getType().intValue());
        }

        //设置图片
        List<String> images = wmNewsDto.getImages();//封面图片
        if (images != null && images.size() != 0) {
            wmNews.setImages(StringUtils.join(images, ","));
        }
        return wmNews;
    }


    /**
     * 添加自媒体图片与素材关系
     *
     * @param wmNews            自媒体图文内容信息
     * @param newsContentImages 自媒体图文内容图片 和 自媒体图文封面图片
     * @param type              引用类型 0内容引用 1主图引用
     * @param ord               引用排序 自动封面类型的排序方式(1单图 2多图) 3前端指定封面类型的排序方式
     */
    private void addWmNewsMaterial(WmNews wmNews, List<String> newsContentImages, Integer type, Integer ord) {
        // 当自媒体图文内容中有图片时 才插入记录
        if (newsContentImages != null && newsContentImages.size() != 0) {
            // select images from wm_news where images in
            //2.2.1 根据自媒体图文内容图片 查询素材
            LambdaQueryWrapper<WmMaterial> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.in(WmMaterial::getUrl, newsContentImages);
            List<WmMaterial> wmMaterials = wmMaterialMapper.selectList(queryWrapper);
            //根据素材信息获取素材id
            List<Integer> wmMaterialIds = wmMaterials
                    .stream()
                    .map(wmMaterial -> wmMaterial.getId())
                    .collect(Collectors.toList());

            //2.2.2 将素材id 和 自媒体图文内容id 添加到 图文素材关系表中
            for (Integer wmMaterialId : wmMaterialIds) {
                WmNewsMaterial wmNewsMaterial = new WmNewsMaterial();
                //图文内容主键id
                wmNewsMaterial.setNewsId(wmNews.getId());
                wmNewsMaterial.setMaterialId(wmMaterialId);
                wmNewsMaterial.setType(type);
                wmNewsMaterial.setOrd(ord);
                wmNewsMaterialMapper.insert(wmNewsMaterial);
            }
        }

        //文章内容审核

    }

    /**
     * 获取自媒体图文内容 图片
     *
     * @param wmNews 自媒体图文
     * @return 图文内容所有图片
     */
    private List<String> getContentImageList(WmNews wmNews) {
        ArrayList<String> newsContentImages = new ArrayList<>();
        String content = wmNews.getContent();
        //获取外面的大 json(继承list接口 是一个list集合)
        JSONArray jsonArray = JSON.parseArray(content);
        //获取里面的每一个json对象 (继承map接口 是个map对象)
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject jsonObject = jsonArray.getJSONObject(i);
            String contentType = jsonObject.getString("type");
            //获取图片类型
            if (contentType.equals("image")) {
                //获取图片信息
                String url = jsonObject.get("value").toString();
                newsContentImages.add(url);
            }
        }
        return newsContentImages;
    }

    /**
     * 文章删除
     *
     * @param id 文章id
     * @return ResponseResult
     */
    @Override
    public ResponseResult delNews(Long id) {
        //参数校验
        if (id == null) {
            throw new CustomException(AppHttpCodeEnum.ARTICLE_ID_INVALID);
        }

        //文章是否存在
        WmNews wmNews = wmNewsMapper.selectById(id);
        if (wmNews == null) {
            throw new CustomException(AppHttpCodeEnum.ARTICLE_NOT_EXIST);
        }
        //存在,判断文章的状态
        Short status = wmNews.getStatus().shortValue();
        Short nowStatus = WmNews.Status.PUBLISHED.getCode();
        //已发布状态,删除失败
        if (nowStatus.equals(status)) {
            // throw new CustomException(AppHttpCodeEnum.ARTICLE_DELETE_ERROR);
            return ResponseResult.errorResult(AppHttpCodeEnum.ARTICLE_DELETE_ERROR);
        }

        //未发布状态,删除成功
        //删除自媒体文章
        wmNewsMapper.deleteById(id);
        //删除自媒体素材中间表
        LambdaQueryWrapper<WmNewsMaterial> newsMaterialWrapper = new LambdaQueryWrapper<>();
        newsMaterialWrapper.eq(WmNewsMaterial::getNewsId, id);
        List<WmNewsMaterial> wmNewsMaterials = wmNewsMaterialMapper.selectList(newsMaterialWrapper);//中间表中有数据,才删除
        if (wmNewsMaterials.size() != 0) {
            LambdaQueryWrapper<WmNewsMaterial> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(WmNewsMaterial::getNewsId, id);
            wmNewsMaterialMapper.delete(wrapper);
        }
        return ResponseResult.okResult(null);
    }

    /**
     * 文章上下架
     *
     * @param wmNewsDto 自媒体文章id 上下架状态0下架 1上架
     */
    @Override
    public void downOrUp(WmNewsDto wmNewsDto) {
        this.wmNewsDto = wmNewsDto;
        //参数校验
        if (wmNewsDto.getId() == null || wmNewsDto.getEnable() == null) {
            throw new CustomException(AppHttpCodeEnum.PARAM_REQUIRE);
        }

        //判断文章是否存在
        WmNews wmNews = wmNewsMapper.selectById(wmNewsDto.getId());
        if (wmNews == null) {
            throw new CustomException(AppHttpCodeEnum.ARTICLE_NOT_EXIST);
        }
        //判断文章是否,发布状态
        if (!(wmNews.getStatus()
                .equals
                        (Integer.valueOf(WmNews.Status.PUBLISHED.getCode() + "")))
        ) {
            throw new CustomException(AppHttpCodeEnum.ARTICLE_DOWN_OR_UP_ERROR);
        }

        //上下架自媒体文章--修改自媒体文章状态
        LambdaUpdateWrapper<WmNews> wmNewsWrapper = new LambdaUpdateWrapper<>();
        wmNewsWrapper.eq(WmNews::getId, wmNewsDto.getId());
        wmNewsWrapper.set(WmNews::getEnable, wmNewsDto.getEnable());
        wmNewsMapper.update(wmNews, wmNewsWrapper);
        //下架app端文章
        Short articleEnable = (wmNewsDto.getEnable() == (short) 0 ? (short) 1 : (short) 0);
        // articleFeignClient.downOrUp(wmNews.getArticleId(), articleEnable);//RPC远程调用修改文章微服务
        //kafka发消息修改文章微服务
        HashMap<String, Object> articleMap = new HashMap<>();
        articleMap.put("articleId", wmNews.getArticleId());
        articleMap.put("articleEnable", articleEnable);
        kafkaTemplate.send(WemediaConstants.ARTICLE_DOWN_OR_UP, JSON.toJSONString(articleMap));

    }

    /**
     * 人工审核分页查询
     *
     * @param pageRequestDto 前端dto
     * @return 当前页显示内容
     */
    @Override
    public Page<WmNewsVo> listVO(PageRequestDto pageRequestDto) {
        this.pageRequestDto = pageRequestDto;
        //非空校验
        if (pageRequestDto == null) {
            throw new CustomException(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        //分页查询
        Page<WmNewsVo> wmNewsVoPage = new Page<>(pageRequestDto.getPage(), pageRequestDto.getSize());
        List<WmNewsVo> wmNewsVoList = wmNewsMapper.selectWmNewsVo(wmNewsVoPage, pageRequestDto);

        //封装最后的page对象
        Page<WmNewsVo> newsVoPage = new Page<>();
        newsVoPage.setCurrent(pageRequestDto.getPage());
        newsVoPage.setSize(pageRequestDto.getSize());
        newsVoPage.setTotal(wmNewsVoPage.getTotal());
        newsVoPage.setRecords(wmNewsVoList);

        return newsVoPage;
    }

    /**
     * 查询文章详情 (wm_news wm_user)
     *
     * @param id 文章id
     * @return 内容
     */
    @Override
    public WmNewsVo oneVO(Long id) {
        if (id == null) {
            throw new CustomException(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        WmNewsVo wmNewsVo = wmNewsMapper.selectWmNewsVoById(id);
        return wmNewsVo;
    }

    /**
     * 人工审核失败(驳回)
     *
     * @param wmAuthDto 文章id 驳回原因
     */
    @Override
    public void authFail(WmAuthDto wmAuthDto) {
        if (wmAuthDto.getMsg() == null || StringUtils.isEmpty(wmAuthDto.getMsg())) {
            throw new CustomException(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        //设置驳回理由 并修改状态2
        // update wm_news set reason = '' where id = '';
        LambdaUpdateWrapper<WmNews> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(WmNews::getReason, wmAuthDto.getMsg())
                .eq(WmNews::getId, wmAuthDto.getId());
        this.update(wrapper);
    }

    /**
     * 人工审核通过
     *
     * @param wmAuthDto 通过审核的文章id
     * @return 结果
     */
    @Override
    public void authPass(WmAuthDto wmAuthDto) {
        if (wmAuthDto.getId() == null) {
            throw new CustomException(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        //自动审核失败,等待人工审核,人工审核通过发布app端文章,修改自媒体文章状态

        // 发布app端文章
        ApArticleDto apArticleDto = new ApArticleDto();
        WmNewsVo wmNewsVo = this.oneVO(wmAuthDto.getId().longValue());
        apArticleDto.setTitle(wmNewsVo.getTitle());
        apArticleDto.setAuthorId(wmNewsVo.getUserId());
        apArticleDto.setAuthorName(wmNewsVo.getAuthorName());
        apArticleDto.setChannelId(wmNewsVo.getChannelId());
        WmChannel wmChannel = wmChannelService.getById(wmNewsVo.getChannelId());
        apArticleDto.setChannelName(wmChannel.getName());//频道名称
        apArticleDto.setLayout(wmNewsVo.getType());//文章布局
        apArticleDto.setImages(wmNewsVo.getImages());
        apArticleDto.setCreatedTime(new Date());
        apArticleDto.setPublishTime(wmNewsVo.getPublishTime());
        apArticleDto.setContent(wmNewsVo.getContent());//文章内容
        ResponseResult<Long> articleId = articleFeignClient.save(apArticleDto);

        //修改自媒体文章状态(已发布),并设置文章id
        LambdaUpdateWrapper<WmNews> wrapper = new LambdaUpdateWrapper<>();
        int code = articleId.getCode();
        if (code == AppHttpCodeEnum.SUCCESS.getCode()) {
            //update wm_news set status = '', article_id = '' where id = '';
            wrapper.set(WmNews::getStatus, Integer.valueOf(WmNews.Status.PUBLISHED.getCode() + ""))
                    .set(WmNews::getArticleId, articleId.getData())
                    .set(WmNews::getReason, "文章审核通过")
                    .eq(WmNews::getId, wmAuthDto.getId());
            this.update(wrapper);
        } else {
            throw new CustomException(AppHttpCodeEnum.SERVER_ERROR);
        }

    }
}




